home *** CD-ROM | disk | FTP | other *** search
- PAGE ,132
- TITLE TTY - Radio Teletype Communications Program
- ;
- ; TTY is a program which allows the IBM Personal
- ; Computer to be used as a radio teletype terminal.
- ;
- ; This program runs under PC-DOS.
- ; The terminal unit must be connected to COM1.
- ; The terminal unit must activate the DATA SET READY
- ; status line to the COM1 port.
- ;
- ; See CQ magazine, November 1983, for an explanation of
- ; this program and how it works on the PC.
- ;
- ; Author: Jack Botner, VE3LNY
- ; BOTNER at TOROLAB
- ; Date: November 1983
- ; Made available to IBMARC by VE3LNY.
- ;
- ; Operation:
- ;
- ; Type 'TTY' from DOS. Select the rtty code and baud rate.
- ; The program then enters receive mode. To transmit, press
- ; F5. To send your CWid at the end of a transmission, press
- ; F6. To return to receive, press F10. To select another
- ; rtty code/baud rate, or end the program, press F10 again.
- ; In receive using Murray code, if noise causes a false
- ; shift, use the F2 key to correct the shift state.
- ;
- ; Note that receive errors are common on RTTY, due to noise
- ; and interference on the signals. This program detects some
- ; of these errors as "framing" errors. The symbol corresponding
- ; to ascii code 15 (decimal) is displayed when one or more
- ; receive errors are detected. This symbol appears like a
- ; double asterisk and tells you that there are receive errors.
- ;
- ;*****************************************************************
- ; Use of this program is subject to the following conditions:
- ; 1. That it be distributed to and used by licenced amateur radio
- ; operators only;
- ; 2. That it be used for amateur radio purposes only;
- ; 3. Under no circumstances can this program be sold or otherwise
- ; used commercially or for profit;
- ; 4. That the origin and purpose of this program not be removed
- ; from this source code file.
- ;*****************************************************************
- ;
- ; Macro Definitions
- DISPLAY MACRO TEXT
- MOV DX,OFFSET TEXT
- MOV AH,9 ;Print String DOS function
- INT 21H ;call DOS
- ENDM
- ;
- LOCATE MACRO
- MOV AH,3 ;Read cursor posn BIOS function
- XOR BH,BH ;Page 0
- INT 10H ;call BIOS
- ENDM
- ;
- SETCRS MACRO
- MOV AH,2 ;set cursor position BIOS function
- XOR BH,BH ;page 0
- INT 10H ;call BIOS
- ENDM
- ;
- SCROLL MACRO
- MOV AH,6 ;Scroll up BIOS function
- XOR CX,CX ;begin row,col = 1,1
- MOV DH,21 ;end row = 22
- MOV DL,79 ;end col = 80
- MOV BH,00000111B ;attribute byte
- INT 10H ;call BIOS
- ENDM
- ;
- ; Equates
- CR EQU 0DH
- LF EQU 0AH
- BEL EQU 0EH ;Bell symbol (display)
- ERR EQU 0FH ;Error symbol for display
- ;
- STACK SEGMENT PARA STACK 'STACK'
- DB 64 DUP ('STACK ')
- STACK ENDS
- ;
- SUBTTL TTY Data and Workarea Definitions
- ;
- DATA SEGMENT PARA PUBLIC 'DATA'
- CWID DB 'DE URCALL$' ;Your call here for CWid
- ;
- ; Communications Parameters Tables for 8250 COM1.
- ; Table entries correspond to fkey descriptions
- ; for Fkeys: F1 F2 F3
- DLABM DB 00AH,06H,04H ;Divisor Latch most significant byte
- DLABL DB 000H,14H,17H ;Divisor latch least significant byte
- LCR DB 004H,04H,3EH ;Line control reg. (bits, parity, etc.)
- RCODE DB 001H,01H,02H ;1=murray (baudot), 2=ascii code
- REQUEST DB 0 ;Which Fkey was selected
- ;
- ; Main selection panel
- PANEL1 DB 'Teletype Terminal Program',CR,LF,CR,LF,CR,LF
- DB 'F1: Murray 45 baud, 5 data bits, 2 stop bits, parity N'
- DB CR,LF,CR,LF
- DB 'F2: Murray 74 baud, 5 data bits, 2 stop bits, parity N'
- DB CR,LF,CR,LF
- DB 'F3: Ascii 110 baud, 7 data bits, 2 stop bits, parity S'
- DB CR,LF,CR,LF
- DB 'F10: END Program$'
- ;
- LIN25 DB 'F2=SHIFT F5=XMIT F6=CWID F10=END$'
- ERR1 DB CR,LF,'No communications adapter address in system.'
- DB CR,LF,'$'
- ERR2 DB CR,LF,'Time-out error on communications adapter.'
- DB ' Check your modem/TU',CR,LF,'$'
- ERR3 DB CR,LF,'Your display must be configured for 80 column'
- DB ' width.',CR,LF,'$'
- ERR4 DB 'and press any key to retry (Esc key to end).'
- DB CR,LF,'$'
- ;
- RMSG DB 'Receiving...$'
- TMSG DB 'Transmitting...$'
- ;
- ; Tables for converting Murray to Ascii & back
- LTRTAB DB 0,'E',LF,'A SIU',CR,'DRJNFCKTZLWHYPQOBG MXV '
- FIGTAB DB 0,'3',LF,'- ',BEL,'87',CR,'$4',27H,',!:(5',22H
- DB ')2#6019?& ./; '
- ;
- ; bit 0: 0 = char defined, 1 = char not defined
- ; bit 1: 0 = LTRS, 1 = FIGS
- ; bit 2: 1 = same code for either shift
- ; bits 3-7: Murray code for character
- ; LF
- MURRAY DB 10 DUP(80H),22H,80H,80H
- ; CR SP ! " # $ % &
- DB 28H,18 DUP(80H),24H,4DH,51H,54H,49H,80H,5AH
- ; ' ( ) * + , - . / 0 1 2 3 4
- DB 4BH,4FH,52H,80H,80H,4CH,43H,5CH,5DH,56H,57H,53H,41H,4AH
- ; 5 6 7 8 9 : ; < = > ? @ A B
- DB 50H,55H,47H,46H,58H,4EH,5EH,80H,80H,80H,59H,80H,03H,19H
- ; C D E F G H I J K L M N O P
- DB 0EH,09H,01H,0DH,1AH,14H,06H,0BH,0FH,12H,1CH,0CH,18H,16H
- ; Q R S T U V W X Y Z ╒\σ^_ '
- DB 17H,0AH,05H,10H,07H,1EH,13H,1DH,15H,11H,5 DUP(80H),4BH
- ; a b c d e f g h i j k l m n
- DB 03H,19H,0EH,09H,01H,0DH,1AH,14H,06H,0BH,0FH,12H,1CH,0CH
- ; o p q r s t u v w x y z {]}~
- DB 18H,16H,17H,0AH,05H,10H,07H,1EH,13H,1DH,15H,11H,5 DUP(80H)
- ;
- LCRAD DW ? ;8250 LCR address
- ; CW Speed Factor - larger number
- SPEED DW 16000 ; means slower CW speed
- CWIDPTR DW ?
- ;
- ; Table for generating CWid.
- ; Each hex byte 'ab' in the table represents the following:
- ; 1. Turn the Break bit on in the comm adapter
- ; 2. Wait 'a' units of time
- ; 3. Turn the Break bit off in the comm adapter
- ; 4. Wait 'b' units of time.
- ; When 'b' equals 2, the character is complete.
- TABLE DB 'A',11H,32H,00H,00H,00H,00H
- DB 'B',31H,11H,11H,12H,00H,00H
- DB 'C',31H,11H,31H,12H,00H,00H
- DB 'D',31H,11H,12H,00H,00H,00H
- DB 'E',12H,00H,00H,00H,00H,00H
- DB 'F',11H,11H,31H,12H,00H,00H
- DB 'G',31H,31H,12H,00H,00H,00H
- DB 'H',11H,11H,11H,12H,00H,00H
- DB 'I',11H,12H,00H,00H,00H,00H
- DB 'J',11H,31H,31H,32H,00H,00H
- DB 'K',31H,11H,32H,00H,00H,00H
- DB 'L',11H,31H,11H,12H,00H,00H
- DB 'M',31H,32H,00H,00H,00H,00H
- DB 'N',31H,12H,00H,00H,00H,00H
- DB 'O',31H,31H,32H,00H,00H,00H
- DB 'P',11H,31H,31H,12H,00H,00H
- DB 'Q',31H,31H,11H,32H,00H,00H
- DB 'R',11H,31H,12H,00H,00H,00H
- DB 'S',11H,11H,12H,00H,00H,00H
- DB 'T',32H,00H,00H,00H,00H,00H
- DB 'U',11H,11H,32H,00H,00H,00H
- DB 'V',11H,11H,11H,32H,00H,00H
- DB 'W',11H,31H,32H,00H,00H,00H
- DB 'X',31H,11H,11H,32H,00H,00H
- DB 'Y',31H,11H,31H,32H,00H,00H
- DB 'Z',31H,31H,11H,12H,00H,00H
- DB '1',11H,31H,31H,31H,32H,00H
- DB '2',11H,11H,31H,31H,32H,00H
- DB '3',11H,11H,11H,31H,32H,00H
- DB '4',11H,11H,11H,11H,32H,00H
- DB '5',11H,11H,11H,11H,12H,00H
- DB '6',31H,11H,11H,11H,12H,00H
- DB '7',31H,31H,11H,11H,12H,00H
- DB '8',31H,31H,31H,11H,12H,00H
- DB '9',31H,31H,31H,31H,12H,00H
- DB '0',31H,31H,31H,31H,32H,00H
- DB '.',11H,31H,11H,31H,11H,32H
- DB ',',31H,31H,11H,11H,31H,32H
- DB '-',31H,11H,11H,11H,32H,00H
- DB '?',11H,11H,31H,31H,11H,12H
- DB '/',31H,11H,11H,31H,12H,00H
- DB 0FFH ;Mark end of table
- ;
- SW1 DB 0 ;Program switches
- SHON EQU 10000000B ;Shift state = FIGS
- TRON EQU 01000000B ;In transmit state
- AERRON EQU 00100000B ;Ascii error flag
- OVRUN EQU 00010000B ;Overrun error occurred bit
- FERON EQU 00001000B ;Last char had framing error bit
- ASCII EQU 00000001B ;0=Murray, 1=ASCII
- ;
- SW2 DB 0
- CRON EQU 10000000B ;Last char was CR
- LFON EQU 01000000B ;Last char was LF
- DATA ENDS
- ;
- SUBTTL TTY Code Segment: Mainline
- ;
- CODE SEGMENT PARA PUBLIC 'CODE'
- ASSUME CS:CODE,DS:DATA,SS:STACK
- TTY PROC FAR
- PUSH DS ;Establish conditions for
- XOR AX,AX ; FAR return to DOS at
- PUSH AX ; end of program.
- MOV AX,DATA
- MOV DS,AX
- MOV ES,AX ;ES=DS
- JMP START
- ;
- ; COM1 receive interrupt routine workarea
- COMADDR DW ? ;8250 Async Adapter Address
- ADBUF DB 32 DUP (?) ;Receive buffer: data
- ERBUF DB 32 DUP (?) ;Receive buffer: status codes
- INPTR DB 0 ;Insert byte count
- OUTPTR DB 0 ;Extract byte count
- ADLEN DB 32 ;Buffer length
- ADCNT DB 0 ;Byte count
- ;
- START: CLD
- ; Make sure display configured for 80 columns
- MOV AH,15 ;Current video state BIOS function
- INT 10H ;call BIOS
- CMP AH,80 ;Width = 80?
- JE IA100
- DISPLAY ERR3 ;Invalid display config.
- JMP PGMEXIT
- ;
- ; The ACA address is taken from the first COM adapter addresses
- ; in the ROM BIOS Data Area, located at segment address 40H.
- ; The COM adapter address is extracted, and validated to make
- ; sure the adapter is actually installed.
- IA100: PUSH ES
- MOV AX,40H
- MOV ES,AX ;ROM BIOS Data Area Segment
- MOV AX,WORD PTR ES:0 ;Get RS232 Base Address
- POP ES
- CMP AX,0
- JNE IA300
- DISPLAY ERR1 ;Invalid adapter specification
- JMP PGMEXIT
- ;
- IA300: MOV COMADDR,AX ;Save RS232 Adapter Address
- ;
- ; Initialize Communications Environment
- ;
- ; Initialize Modem Control Register with DTR flag
- MOV DX,COMADDR ;Reload adapter address
- ADD DX,4 ;Address Modem Control Register (3FC)
- MOV AL,00000001B ;Turn DTR flag on, all others off
- OUT DX,AL ;Write MCR register
- ;
- ; Receive Modem Status Register from adapter
- IA500: MOV CX,22 ;Establish time-out count
- MOV DX,COMADDR ;Reload adapter address
- ADD DX,6 ;Modem Status Register Address (3FE)
- ;
- IC100: IN AL,DX ;Read Modem Status Register
- TEST AL,00100000B ;Test Data Set Ready flag
- JZ IC300 ;DSR off - process error
- JMP IE100 ;DSR is on - continue
- ;
- IC300: CALL PAUSE ;Retry CX times before giving up,
- LOOP IC100 ; waiting PAUSE between retries
- ;
- ; Process time-out error by giving user chance to try again
- DISPLAY ERR2 ;State error
- DISPLAY ERR4 ;State action
- ; Get response
- MOV AH,0CH ;Clr kybd DOS req
- MOV AL,7 ;Then direct console input req
- INT 21H ;Call DOS
- CMP AL,0 ;Returned keystroke
- JNE ID100 ;Not extended ASCII
- ; Discard extended ascii code
- MOV AH,7 ;Direct console input req
- INT 21H ;Call DOS
- JMP IA500 ;Retry test for DSR
- ;
- ID100: CMP AL,27 ;ESCape key?
- JE ID300
- JMP IA500 ;Retry test for DSR
- ID300: JMP PGMEXIT ;That's all, folks
- ;
- ; Establish 0C interrupt handling routine vector.
- IE100: PUSH DS
- MOV AH,25H ;Set Interrupt Vector DOS function
- MOV AL,0CH ;Interrupt type
- MOV CX,CS
- MOV DS,CX
- MOV DX,OFFSET INT0C ;ENTRY_0C
- INT 21H ;Call DOS
- POP DS
- ;
- ; Enable IRQ4 interrupt on 8259 interrupt controller
- IN AL,21H ;Read IMR
- AND AL,11101111B ;Turn off IRQ4 bit to enable interrupt
- OUT 21H,AL ;Write OCW1 (IMR)
- ;
- ; Enter here to re-set communications parameters
- ;
- ; Display TTY Initial Selection Panel
- INITIALIZE:
- CALL CLEAR ;Clear the screen
- MOV DH,3 ;Row=4
- XOR DL,DL ;Col=1
- SETCRS ;Set cursor address to locate panel
- ;
- DISPLAY PANEL1 ;Display selection panel
- ;
- IG100: MOV AH,8 ;Console input DOS req
- INT 21H ;Call DOS
- CMP AL,0 ;0=extended ascii code returned
- JZ IG300 ;Look for F1-F10
- JMP IG100 ;Pressed wrong key
- ;
- IG300: MOV AH,8 ;Console input DOS req
- INT 21H ;Call DOS
- CMP AL,59 ;F1
- JE IG500
- CMP AL,60 ;F2
- JE IG500
- CMP AL,61 ;F3
- JE IG500
- CMP AL,68 ;F10
- JE IG500
- JMP IG100
- ;
- IG500: PUSH AX
- CALL CLEAR ;Clear the screen
- XOR DX,DX ;Row 1, col 1
- SETCRS ;Set cursor position
- POP AX
- ;
- CMP AL,68 ;F10?
- JNE IH100 ;No, select baud etc.
- JMP END_RUN ;Run complete
- ;
- IH100: SUB AL,58 ;Make number relative to 0
- MOV REQUEST,AL ;Save fkey number
- SUB BX,BX
- MOV BL,AL ;Create index register for
- DEC BX ; table lookup
- ;
- ; Write 1 into Divisor Latch Access Bit of Line Control Register
- ; to allow access to Divisor Latches (Baud Rate Generator).
- MOV DX,COMADDR ;Load adapter address
- ADD DX,3 ;Point to 8250 control register (3FB)
- MOV AL,80H
- OUT DX,AL ;Set DLAB=1 (divisor latch access bit)
- ;
- ; Write high-order byte of baud rate divisor to Divisor Latch
- MOV DX,COMADDR ;Reload adapter address
- INC DX ;Divisor Latch Most Sig. Bits (3F9)
- MOV AL,DLABM╒BXσ ;Baud rate
- OUT DX,AL ;Set baud rate Most Significant Bits
- ;
- ; Write low-order byte of baud rate divisor to Divisor Latch
- DEC DX ;Divisor Latch Least Sig. Bits (3F8)
- MOV AL,DLABL╒BXσ ;Baud rate
- OUT DX,AL ;Set Baud Rate Least Significant bits
- ;
- ; Write Line Control Register to set Data Bits, Stop Bits, Parity,
- ; and reset Divisor Latch Access Bit.
- ADD DX,3 ;Point to 8250 control reg. (3FB)
- MOV AL,LCR╒BXσ ;Set Parity, Stop Bits, Word Lenth
- OUT DX,AL ;Send Line Control Register Data
- ;
- ; Write Interrupt Enable Register to enable 8250 interrupt.
- ; Update Modem Control Register to enable interrupts
- CALL ENAINT ;Enable interrupt for receive
- ;
- ; Get code selection and build info lines
- AND SW1,0FFH-ASCII ;Indicate Murray mode
- MOV AL,RCODE╒BXσ
- CMP AL,02
- JNE II100
- OR SW1,ASCII ;Indicate ASCII mode
- ;
- ; Display Fkey description line 25
- II100: MOV DH,24 ;Row 25
- XOR DL,DL ;Col 1
- SETCRS
- DISPLAY LIN25
- ;
- XOR DX,DX ;Row,col = 1,1
- SETCRS
- AND SW1,0FFH-TRON-SHON-FERON
- ;
- ; Scan keyboard for requests
- ;
- READ_KEYBD:
- MOV AH,0BH ;Check Keyboard Status DOS code
- INT 21H ;Invoke DOS
- CMP AL,0 ;00=no character available
- JNE MA100
- JMP MF400
- ;
- MA100: MOV AH,8 ;Keyboard Input DOS code
- INT 21H ;Call DOS
- CMP AL,0 ;If AL=0 then char is extended ASCII code
- JE MB100 ;Go read second character
- TEST SW1,TRON ;If receive mode, ignore character typed
- JZ MA500 ; on keyboard and go poll adapter
- JMP SEND_ADAPTER
- MA500: JMP READ_ADAPTER
- ;
- ; Process Extended ASCII code for function key requests.
- MB100: MOV AH,8 ;Keyboard Input again
- INT 21H ;Invoke DOS
- CMP AL,59
- JB MB500 ;Check for F1-F10 range
- CMP AL,68
- JNA MC300
- ;
- MB500: TEST SW1,TRON
- JNZ MC100 ;In receive mode, go scan ACA
- JMP READ_ADAPTER ; for received character.
- MC100: JMP READ_KEYBD
- ;
- MC300: SUB AL,58 ;F1-F10 selected.
- ;
- CMP AL,2 ;Check for F2 key (Toggle Shift)
- JNE MD300
- TEST SW1,ASCII ;Does not apply to ASCII mode
- JNZ MC500
- TEST SW1,TRON ;Allow in receive mode only
- JZ MC700
- MC500: JMP MF200 ;Sound alarm and continue
- ;
- MC700: TEST SW1,SHON ;Process toggle shift
- JZ MD100
- AND SW1,0FFH-SHON ;Turn the switch off
- JMP MF400
- MD100: OR SW1,SHON ;Turn the switch on
- JMP MF400
- ;
- MD300: CMP AL,5 ;Check for F5 key (transmit request)
- JNE ME100
- TEST SW1,TRON ;Allow in receive mode only
- JZ MD500
- JMP MF200 ;Sound alarm and continue
- ;
- MD500: AND SW1,0FFH-SHON ;Reset to LTRS shift
- OR SW1,TRON ;Set transmit mode
- MOV DX,OFFSET TMSG
- CALL DISPLAY_MESSAGE
- CALL DISINT ;Disable 8250 adapter interrupts
- ;
- CALL RTSON ;Turn on request-to-send signal
- JMP MF400
- ;
- ME100: CMP AL,6 ;Check for F6 key (send CW ID)
- JNE ME400
- TEST SW1,TRON
- JNZ ME300 ;Invalid request if in receive mode
- JMP MF200 ;Sound alarm and continue
- ;
- ME300: CALL CWID_RTN ;send CW ID
- JMP MF400 ;OK
- ;
- ME400: CMP AL,10 ;Check for F10 key (END)
- JE ME500
- JMP MF200 ;Go sound alarm for bad Fkey
- ;
- ME500: TEST SW1,TRON ;In transmit mode?
- JNZ ME700
- JMP MF100
- ;
- ME700: AND SW1,0FFH-TRON ;Return to receive mode here
- MOV DX,OFFSET RMSG
- CALL DISPLAY_MESSAGE
- ;
- CALL ENAINT ;Enable 8250 adapter interrupts
- CALL RTSOFF ;Turn off request-to-send signal
- JMP MF400 ;Done with this request
- ;
- MF100: CALL DISINT ;Disable 8250 adapter interrupts
- CALL RTSOFF ;Turn off request-to-send signal
- JMP INITIALIZE ;Return to main menu
- ;
- MF200 LABEL NEAR
- CALL ALARM ;Error or undefined key selected
- ;
- MF400: TEST SW1,TRON ;End of F1-F10 processing
- JNZ MG100
- JMP READ_ADAPTER ;In receive, continue scanning adapter
- MG100: JMP READ_KEYBD
- ;
- ; Communicatiins Adapter SEND routine
- ;
- SEND_ADAPTER: ;Char from keyboard in AL
- SUB AH,AH
- AND AL,01111111B ;Make sure high order bit is zero.
- TEST SW1,ASCII
- JZ MH100
- MOV DL,AL ;ASCII: use character as entered
- JMP MH200
- ;
- MH100: MOV SI,AX ;Murray: translate required
- MOV DL,MURRAY╒SIσ ;Get Murray equivalent of ASCII
- TEST DL,10000000B ;Test for invalid character
- JZ MH200
- CALL ALARM ;Sound the alarm
- JMP MJ500 ;Bypass invalid character
- ;
- MH200: PUSH DX
- MOV DL,AL
- CALL DISPLAY_CHAR
- POP DX
- ;
- TEST SW1,ASCII ;Bypass shift jazz for ASCII
- JZ MH400
- JMP MI200
- MH400: TEST DL,00100000B ;Test shift irrelevant bit
- JNZ MI100
- TEST DL,01000000B ;Test for shift
- JZ MH600
- ; Char to send is FIGS
- TEST SW1,SHON ;What was sent last?
- JNZ MI100
- MOV AL,1BH ;1B = FIGS
- CALL XMIT_CHAR
- OR SW1,SHON ;Indicate in FIGS shift now
- JMP MI100
- ;
- MH600: TEST SW1,SHON ;char to send is LTRS
- JZ MI100
- MOV AL,1FH ;1F = LTRS
- CALL XMIT_CHAR
- AND SW1,0FFH-SHON ;Indicate in LTRS shift now
- ;
- MI100: AND DL,00011111B
- ; Write char in DL to async adapter
- MI200: MOV AL,DL ;Char to send
- CALL XMIT_CHAR
- ;
- TEST SW1,ASCII ;Bypass shift jazz for ASCII
- JNZ MI500
- CMP DL,8 ;If a CR was sent (Murray 08H),
- JE MI400 ; then a LF must also be sent
- JMP MJ500
- ;
- MI400: MOV DL,2 ;LF = Murray 02H
- JMP MJ300
- ;
- MI500: CMP DL,CR ;If CR was sent (ASCII),
- JE MJ100 ; then a LF must also be sent
- JMP MJ500
- ;
- MJ100: MOV DL,LF
- ; Write character in DL to ACA
- MJ300: MOV AL,DL ;Char to send
- CALL XMIT_CHAR
- MOV DL,LF ;Send to display too
- CALL DISPLAY_CHAR
- MJ500: JMP READ_KEYBD
- ;
- ; Communications Adapter READ routine
- ;
- READ_ADAPTER:
- CMP ADCNT,0 ;See if anything is in the buffer
- JA MK100
- JMP READ_KEYBD ;Buffer is empty - continue elsewhere
- ;
- ; The following statuses (of interest) are possible in ERBUF:
- ; Bit 3 = FRAMING ERROR Bit 1 = OVERRUN ERROR
- MK100: CLI ;no interrupts
- SUB BH,BH
- MOV BL,OUTPTR
- MOV AH,ERBUF╒BXσ ;load status byte
- MOV AL,ADBUF╒BXσ ;load data byte
- INC BL
- CMP BL,ADLEN ;perform maintenance on buffer pointer
- JB MK300
- SUB BL,BL
- MK300: MOV OUTPTR,BL
- DEC ADCNT
- STI ;Interrupts OK now
- ;
- TEST AH,00000010B ;Overrun error?
- JZ MK500
- OR SW1,OVRUN ;Indicate overrun error occurred
- JMP READ_ADAPTER ;throw away byte
- ;
- MK500: TEST AH,00001000B ;Framing error?
- JZ ML200
- TEST SW1,FERON ;Was the last character in error too?
- JZ ML100
- JMP READ_ADAPTER ;Yes, ignore this character (gibberish)
- ;
- ML100: OR SW1,FERON ;No, turn on error indicator
- MOV DL,ERR ;Indicate error occurred
- JMP MM700
- ;
- ML200: AND SW1,0FFH-FERON ;RESET error switch
- TEST SW1,ASCII ;don't translate ASCII, of course
- JZ ML700
- ;
- ; Validate ASCII character
- MOV DL,AL ;check ASCII for obvious errors
- CMP DL,1FH
- JA ML500
- CMP DL,CR ;DL is less than 20H, which might be bad
- JE ML500
- CMP DL,LF
- JE ML500
- TEST SW1,AERRON ;was last character in error too?
- JZ ML400
- JMP READ_ADAPTER
- ML400: MOV DL,ERR ;substitute error code
- OR SW1,AERRON
- JMP MM700
- ML500: AND SW1,0FFH-AERRON
- JMP MM500
- ;
- ; Translate MURRAY code to ASCII
- ML700: SUB AH,AH ;AL contains Murray character
- AND AL,00011111B ;Make sure high 3 bits are off
- MOV BX,AX ; and use as base register
- CMP AL,1BH ;FIGS character?
- JNE MM100
- OR SW1,SHON ;Set status to FIGS
- JMP READ_ADAPTER ;Go read another character
- ;
- MM100: CMP AL,1FH ;LTRS character?
- JNE MM200
- AND SW1,0FFH-SHON ;Set status to LTRS
- JMP READ_ADAPTER ;Go read another character
- ;
- MM200: TEST SW1,SHON ;Is it FIGS?
- JZ MM400
- ; Translate FIGS character
- MOV DL,FIGTAB╒BXσ
- JMP MM500
- ; Translate LTRS character
- MM400: MOV DL,LTRTAB╒BXσ
- ;
- MM500: CMP DL,0 ;BLANK char?
- JNE MM700
- JMP READ_ADAPTER ;BLANK=no print or carriage movement
- ;
- MM700: CALL DISPLAY_CHAR
- JMP READ_KEYBD
- ;
- SUBTTL Restore Communications Environment
- END_RUN:
- ;
- ; Disable Interrupt Enable Register flag
- CALL DISINT
- ;
- ; Disable IRQ4 interrupt on 8259 interrupt controller
- IN AL,21H ;Read IMR
- OR AL,00010000B ;turn on IRQ4 bit to disable interrupt
- OUT 21H,AL ;Write OCW1 (IMR)
- ;
- ; Clear 0C interrupt handling routine vector.
- PUSH DS
- MOV AH,25H ;Set Interrupt Vector DOS function
- MOV AL,0CH ;Interrupt type
- XOR DX,DX ;clear address
- MOV DS,DX
- INT 21H ;call DOS
- POP DS
- ;
- ; Write Modem Control Register to clear flags
- MOV DX,COMADDR ;Load adapter address
- ADD DX,4 ;Address modem control register (3FC)
- MOV AL,0 ;All flags clear
- OUT DX,AL ;Write MCR register
- ;
- CALL CLEAR ;Clear the screen
- MOV AH,2 ;Set cursor position BIOS function
- XOR DX,DX ;Row,col = 1,1
- XOR BH,BH ;Page 0
- INT 10H ;Call BIOS
- ;
- PGMEXIT: RET ;Return to DOS
- TTY ENDP
- ;
- ; Display character in DL routine
- ;
- DISPLAY_CHAR PROC NEAR
- PUSH AX
- PUSH BX
- PUSH CX
- CMP DL,CR
- JNE SA200
- OR SW2,CRON ;Process carrier return
- LOCATE
- ; DH = Row, DL = column of cursor position
- XOR DL,DL ;Column = 1
- SETCRS ;Set cursor position
- JMP SA900
- ;
- SA200: CMP DL,LF
- JNE SA400
- OR SW2,LFON ;Process line feed
- LOCATE
- ; DH = Row, DL = column of cursor position
- INC DH ;Next row
- CMP DH,21 ;Past row 22?
- JNA SA300
- ;
- PUSH DX
- MOV AL,1 ;Scroll 1 line
- SCROLL
- POP DX
- MOV DH,21 ;Row = 22
- ;
- SA300: SETCRS ;Set cursor position
- JMP SA900
- ;
- SA400: TEST SW2,CRON ;Process the character
- JZ SA600
- TEST SW2,LFON ;If preceding CR not accompanied by
- JNZ SA600 ; LF, corrective action is necessary
- ;
- LOCATE
- ; DH = Row, DL = column of cursor position
- INC DH ;Next row
- CMP DH,21 ;Past row 22?
- JNA SA500
- ;
- PUSH DX
- MOV AL,1 ;Scroll 1 line
- SCROLL
- POP DX
- MOV DH,21 ;Row = 22
- ;
- SA500: SETCRS ;Set cursor position
- ;
- SA600: MOV AH,9 ;Write char BIOS function
- XOR BH,BH ;Page = 0
- MOV CX,1 ;Number of characters
- MOV AL,DL ;Character
- MOV BL,00000111B ;Attribute byte
- INT 10H ;Call BIOS
- AND SW2,0FFH-CRON-LFON
- ;
- LOCATE ;Read cursor position
- ; DH = Row, DL = column of cursor position
- INC DL ;Next column
- CMP DL,79 ;Past end of row?
- JNA SA700
- ;
- XOR DL,DL ;Reset to column 1
- INC DH ;Next row
- CMP DH,21 ;Past row 22?
- JNA SA700
- ;
- MOV AL,1 ;Scroll 1 line
- SCROLL
- MOV DH,21 ;Set cursor to row 22
- MOV DL,0 ;Set cursor to column 1
- ;
- SA700: SETCRS ;Set cursor position
- ;
- SA900: POP CX
- POP BX
- POP AX
- RET
- DISPLAY_CHAR ENDP
- ;
- ; Display a Message routine
- ;
- DISPLAY_MESSAGE PROC NEAR
- PUSH AX
- PUSH BX
- PUSH CX
- PUSH DX
- LOCATE ;Read cursor position
- ; DH = Row, DL = column of cursor position
- ADD DH,2 ;Add 2 giving target row
- CMP DH,21 ;Compare with line 22
- JA SC100
- JB SC300 ;No scroll required
- MOV AL,1 ;Scroll 1 line only
- JMP SC200
- ;
- SC100: MOV AL,2 ;Scroll 2 lines
- ;
- SC200: SCROLL ;Scroll up AL lines
- ;
- MOV DH,21 ;Set cursor to row 22
- ;
- SC300: MOV DL,0 ;Set cursor to column 1
- SETCRS ;Set cursor position
- ;
- POP DX ;Restore message offset
- MOV AH,9 ;Print String DOS function
- INT 21H ;Call DOS
- ;
- LOCATE ;Read cursor position
- ;
- ADD DH,2 ;Add 2 giving target row
- CMP DH,21 ;Compare with line 22
- JA SC400
- JB SC600 ;No scroll required
- MOV AL,1 ;Scroll 1 line only
- JMP SC500
- ;
- SC400: MOV AL,2 ;Scroll 2 lines
- ;
- SC500: SCROLL ;Scroll up AL lines
- MOV DH,21 ;set cursor to row 22
- ;
- SC600: MOV DL,0 ;column = 1
- SETCRS ;set cursor position
- ;
- SC900: POP CX
- POP BX
- POP AX
- RET
- DISPLAY_MESSAGE ENDP
- ;
- ; Send CWID Routine
- ;
- CWID_RTN PROC NEAR
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH SI
- CLD
- ;
- MOV DX,COMADDR ;Point to 8250 Line Control register
- ADD DX,3
- MOV LCRAD,DX ;Save LCR address
- IN AL,DX ;Read current setting of LCR
- TEST AL,01000000B ;Is set break bit on?
- JZ SF100
- AND AL,10111111B ;If break bit is on, turn it off
- OUT DX,AL ; and send it back to the adapter
- ;
- SF100: MOV AL,10
- CALL CWID_PAUSE ;Pause before sending ID
- MOV AX,OFFSET CWID
- MOV CWIDPTR,AX
- ;
- SF200: MOV SI,CWIDPTR
- MOV AL,BYTE PTR ╒SIσ
- CMP AL,'$' ;End of message?
- JNE SF300
- JMP SG800 ;All done
- ;
- SF300: CMP AL,' ' ;Space?
- JNE SF500
- ;
- SF400: MOV AL,2
- CALL CWID_PAUSE ;Pause between words
- JMP SG500
- ;
- SF500: MOV BX,OFFSET TABLE
- ; Search for character in table
- SF600: MOV AH,BYTE PTR ╒BXσ
- CMP AH,0FFH ;End of the table?
- JNE SG100
- JMP SF400 ;Letter not found in table
- ;
- SG100: CMP AL,AH ;Is this the entry we want?
- JE SG200
- ADD BX,7 ;Try next entry in table
- JMP SF600
- ;
- SG200: INC BX
- MOV AL,BYTE PTR ╒BXσ
- MOV AH,AL
- MOV CL,4
- SHR AH,CL ;Extract high-order digit
- AND AL,0FH ;Extract low-order digit
- ;
- MOV CX,AX
- MOV DX,LCRAD
- IN AL,DX ;Read current setting of LCR
- OR AL,01000000B ;Turn the break bit on
- OUT DX,AL ;Send new LCR register contents
- MOV AL,CH ;Table byte (value = 1, 2 or 3)
- CALL CWID_PAUSE
- ;
- IN AL,DX ;Read current setting of LCR
- AND AL,10111111B ;Turn the break bit off
- OUT DX,AL ;Send new LCR register contents
- MOV AL,CL ;Table byte (value = 1, 2 or 3)
- CALL CWID_PAUSE
- ;
- CMP CL,2 ;2 = character complete
- JE SG500
- JMP SG200 ;Process next segment of character
- ;
- SG500: INC CWIDPTR ;On to next character
- JMP SF200
- ;
- SG800: POP SI
- POP DX
- POP CX
- POP BX
- RET
- CWID_RTN ENDP
- ;
- CWID_PAUSE PROC NEAR ;relative delay in AL (1-8)
- PUSH CX
- CMP AL,2 ;2 means end-of-character
- JNE SJ100
- MOV AL,3 ;Wait 3 after character complete too
- ;
- SJ100: MOV CX,SPEED
- SJ200: LOOP SJ200 ;Wait awhile
- DEC AL
- OR AL,AL ;Test for zero
- JNZ SJ100
- POP CX
- RET
- CWID_PAUSE ENDP
- ;
- SUBTTL Enable interrupt on 8250 communications adapter
- ;
- ENAINT PROC NEAR
- ;
- ; Write Interrupt Enable Register to enable 8250 interrupt.
- MOV DX,COMADDR ;Reload adapter address
- INC DX ;Address Interrupt Enable Reg. (3F9)
- MOV AL,1 ;Enable Data Available Interrupt
- OUT DX,AL ;Send Interrupt Enable Register Data
- ;
- ; Update Modem Control Register to enable interrupts
- ADD DX,3 ;Address modem control register (3FC)
- IN AL,DX ;Present MCR contents
- OR AL,00001000B ;Turn ON OUT2 flag
- OUT DX,AL ;rewrite MCR register
- ;
- ; If an interrupt is pending, the 8250 does not honor the enable
- ; until it is cleared.
- SUB DX,2 ;Interrupt ID. Reg. (3FA)
- IN AL,DX ;read Interrupt ID port
- TEST AL,00000001B ;0 if interrupt pending
- JNZ SM900
- SUB DX,2 ;Receiver Buffer Reg. (3F8)
- IN AL,DX ;clear pending interrupt - discard byte
- SM900: RET
- ENAINT ENDP
- ;
- SUBTTL Disable interrupts on 8250 communications adapter
- ;
- DISINT PROC NEAR
- ;
- ; Write Interrupt Enable Register to disable 8250 interrupt.
- MOV DX,COMADDR ;Reload adapter address
- INC DX ;Point to Interrupt Enable Register (3F9
- MOV AL,0 ;Disable all interrupts
- OUT DX,AL ;Send Interrupt Enable Register Data
- ;
- ; Update Modem Control Register to disable interrupts
- ADD DX,3 ;Point to modem control register (3FC)
- IN AL,DX ;Present MCR contents
- AND AL,11110111B ;Turn OUT2 OFF
- OUT DX,AL ;Rewrite MCR register
- RET
- DISINT ENDP
- ;
- SUBTTL Turn ON/OFF Request to Send signal
- ;
- RTSON PROC NEAR
- ;
- ; Update Modem Control Register to turn on RTS flag
- MOV DX,COMADDR ;Comm Adapter Address
- ADD DX,4 ;point to modem control register (3FC)
- IN AL,DX ;get current contents of register
- OR AL,00000010B ;Turn bit 1 ON (RTS line)
- OUT DX,AL ;rewrite MCR register
- RET
- RTSON ENDP
- ;
- RTSOFF PROC NEAR
- ;
- ; Update Modem Control Register to turn off RTS flag
- MOV DX,COMADDR ;Comm Adapter Address
- ADD DX,4 ;point to modem control register (3FC)
- IN AL,DX ;get current contents of register
- AND AL,11111101B ;Turn bit 1 OFF (RTS line)
- OUT DX,AL ;Rewrite MCR register
- RET
- RTSOFF ENDP
- ;
- ; Send character in AL
- XMIT_CHAR PROC NEAR
- PUSH DX
- PUSH AX ;Save input character
- ;
- XM200: MOV DX,COMADDR ;Load adapter address
- ADD DX,5 ;Adress of Line Status Reg. (3FD)
- IN AL,DX ;Read LSR
- TEST AL,00100000B ;Test TX hold register empty?
- JNZ XM400 ;Ready to accept data
- JMP XM200 ;Not ready so try again
- ;
- XM400: MOV DX,COMADDR ;Load adapter address THR (3F8)
- POP AX ;Restore character
- OUT DX,AL ;Write to THR
- POP DX
- RET
- XMIT_CHAR ENDP
- ;
- PAUSE PROC NEAR ;PAUSE routine
- PUSH CX
- XOR CX,CX
- SP100: LOOP SP100
- POP CX
- RET
- PAUSE ENDP
- ;
- CLEAR PROC NEAR ;CLEAR SCREEN Routine
- MOV AH,6 ;Scroll up BIOS function
- MOV AL,0 ;Clear screen request
- XOR CX,CX ;Start row,col = 1,1
- MOV DH,24 ;End row = 25
- MOV DL,79 ;End col = 80
- MOV BH,00000111B ;Attribute byte
- INT 10H ;Call BIOS
- ;
- RET
- CLEAR ENDP
- ;
- SUBTTL ALARM - Sound the ALARM
- ;
- TIMER EQU 40H
- PORT_B EQU 61H ;8255 port B addr
- ;
- ALARM PROC NEAR
- PUSH CX
- CLD
- MOV AL,10110110B ;SEL TIM 2, LSB,MSB,Binary
- OUT TIMER+3,AL ;Write the Timer Mode Reg
- MOV AX,400H
- OUT TIMER+2,AL ;Write Timer 2 cnt - LSB
- MOV AL,AH
- OUT TIMER+2,AL ;Write Timer 2 cnt - MSB
- IN AL,PORT_B ;Get current setting of port
- MOV AH,AL ;Save the setting
- OR AL,03 ;Turn speaker on
- OUT PORT_B,AL
- SUB CL,CL ;Set cnt to wait awhile
- MOV CH,64
- ST100: LOOP ST100 ;Delay before turning off
- MOV AL,AH ;Recover value of port
- OUT PORT_B,AL
- POP CX
- RET
- ALARM ENDP
- ;
- SUBTTL TTYINTR - Adapter Interrupt 0C Routine
- ;
- INT0C PROC FAR
- STI ;Enable interrupts
- PUSH AX
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH SI
- PUSH DI
- CLD
- ;
- SW100: MOV DX,COMADDR ;Load adapter address
- ADD DX,5 ;Address the Line Status Register (3FD)
- IN AL,DX ;Read Line Status Register
- TEST AL,01H ;Test Data Ready bit
- JNZ SW300 ;One means data is available in receive
- JMP SW900 ;No data, so quit
- ;
- ; The following statuses (of interest) are possible in AL:
- ; Bit 3 = FRAMING ERROR Bit 1 = OVERRUN ERROR
- SW300: MOV CL,AL ;Save status byte in CL
- MOV DX,COMADDR ;Get Receive Buffer Register addr (3F8)
- IN AL,DX ;Read one byte from adapter
- MOV CH,AL ;Save data byte in CH
- ;
- SUB BH,BH
- MOV BL,INPTR
- MOV ADBUF╒BXσ,CH ;Store data byte in buffer
- MOV ERBUF╒BXσ,CL ;Store status byte in buffer
- ;
- INC BL ;Point to next byte in buffers
- CMP BL,ADLEN ;Check for wrap-around in buffer
- JB SW500
- SUB BL,BL ;Reset pointer at wrap-around
- SW500: MOV INPTR,BL ;Update pointer
- MOV CL,ADCNT
- INC CL ;Increment active byte count
- CMP CL,ADLEN ;Check for buffer overrun
- JNA SW700
- MOV CL,1 ;Throw away buffer contents when overrun
- SW700: MOV ADCNT,CL
- ;
- SW900: CLI ;Disable interrupts
- MOV AL,20H ;Signal end of interrupt to
- OUT 20H,AL ; 8259 via OCW2 register
- POP DI
- POP SI
- POP DX
- POP CX
- POP BX
- POP AX
- IRET
- INT0C ENDP
- ;
- CODE ENDS
- END TTY
-